﻿/*
Copyright (c) 2008 William Duff

Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.
*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.ComponentModel;
using System.Globalization;

namespace LiveUpload.Facebook
{
    /// <summary>
    /// Data related to the temporary publishing session.
    /// </summary>
    public class SessionData
    {
        #region Constructors

        /// <summary>
        /// Constructs a new SessionData object to encapsulate sessionXml.
        /// </summary>
        /// <param name="sessionXml">
        /// The sessionXml file passed by the IPublishPlugin interface.
        /// </param>
        public SessionData(XmlDocument sessionXml)
        {
            if (sessionXml == null)
            {
                throw new ArgumentNullException("sessionXml");
            }
            this.sessionXml = sessionXml;

            this.publishParametersNode = GetXmlElement("PublishParameters", 
                this.sessionXml.DocumentElement);

            this.maxWidth = MaxWidthExists() ? GetMaxWidth() : 0;
            this.maxHeight = MaxHeightExists() ? GetMaxHeight() : 0;
            this.apiKey = ApiKeyExists() ? GetApiKey() : string.Empty;
            this.apiSecret = ApiSecretExists() ? GetApiSecret() : string.Empty;
            this.user = UserExists() ? GetUser() : null;
            this.album = AlbumExists() ? GetAlbum() : null;
            this.itemSet = ItemSetExists() ? GetItemSet() : new List<Item>();
            this.log = LogExists() ? GetLog() : new List<LogItem>();
            this.friendList = FriendListExists() ? GetFriendList() : new List<Friend>();
            this.accountLinks = AccountLinksExists() ? GetAccountLinks() : new List<AccountLink>();
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// The sessionXml file passed by the IPublishPlugin interface.
        /// </summary>
        private XmlDocument sessionXml;

        /// <summary>
        /// Points to the "PublishParameters" XmlNode inside sessionXml.
        /// </summary>
        private XmlNode publishParametersNode;

        // Private fields.
        private int maxWidth;
        private int maxHeight;
        private string apiKey;
        private string apiSecret;
        private Account user;
        private Album album;
        private List<Item> itemSet;
        private List<LogItem> log;
        private List<Friend> friendList;
        private Dictionary<string, PersonTag> uniquePeopleTags;
        private List<AccountLink> accountLinks;

        #endregion

        #region Public Fields

        /// <summary>
        /// The maximum width a photo should be published at.
        /// </summary>
        public int MaxWidth
        {
            get { return this.maxWidth; }
            set { this.maxWidth = value; }
        }

        /// <summary>
        /// The maximum height a photo should be published at.
        /// </summary>
        public int MaxHeight
        {
            get { return this.maxHeight; }
            set { this.maxHeight = value; }
        }

        /// <summary>
        /// A unique identifier for this application that is passed as a URL parameter to access 
        /// Facebook API features.
        /// </summary>
        public string ApiKey
        {
            get { return this.apiKey; }
            set { this.apiKey = value; }
        }

        /// <summary>
        /// A secret identifier for this application that is passed as a URL parameter to Facebook.
        /// </summary>
        public string ApiSecret
        {
            get { return this.apiSecret; }
            set { this.apiSecret = value; }
        }

        /// <summary>
        /// The Facebook user we wish to upload with.
        /// </summary>
        public Account User
        {
            get { return this.user; }
            set { this.user = value; }
        }

        /// <summary>
        /// An album, owned by the user, to upload to.
        /// </summary>
        public Album Album
        {
            get { return this.album; }
            set { this.album = value; }
        }

        /// <summary>
        /// The list of items that were initially passed in the sessionXml document.
        /// </summary>
        public List<Item> ItemSet
        {
            get { return this.itemSet; }
        }

        /// <summary>
        /// A log of all successful and unsuccessful API actions.
        /// </summary>
        public List<LogItem> Log
        {
            get { return this.log; }
            set { this.log = value; }
        }

        /// <summary>
        /// The list of friends for this user.
        /// </summary>
        public List<Friend> FriendList
        {
            get { return this.friendList; }
            set { this.friendList = value; }
        }

        /// <summary>
        /// The list of unique people tags, indexed by name.
        /// </summary>
        public Dictionary<string, PersonTag> UniquePeopleTags
        {
            get { return this.uniquePeopleTags; }
            set { this.uniquePeopleTags = value; }
        }

        /// <summary>
        /// The list of links between WLPG people tags and Facebook accounts.
        /// </summary>
        public List<AccountLink> AccountLinks
        {
            get { return this.accountLinks; }
            set { this.accountLinks = value; }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Gets an XmlElement, assuming it exists.
        /// </summary>
        /// <param name="elementName">
        /// The name of the element.
        /// </param>
        /// <param name="parentNode">
        /// The immediate parent of the element.
        /// </param>
        /// <returns>
        /// The specified XmlElement.
        /// </returns>
        private XmlElement GetXmlElement(string elementName, XmlNode parentNode)
        {
            if (elementName == null)
            {
                throw new ArgumentNullException("element");
            }
            if (parentNode == null)
            {
                throw new ArgumentNullException("parentNode");
            }

            XmlElement theElement = parentNode.SelectSingleNode(elementName) as XmlElement;
            if (theElement == null)
            {
                throw new ArgumentException(elementName + " does not exist.", "elementName");
            }
            return theElement;
        }

        /// <summary>
        /// Sets an XmlElement, replacing an existing XmlElement if necessary.
        /// </summary>
        /// <param name="element">
        /// The element to set.
        /// </param>
        /// <param name="parentNode">
        /// The immediate parent of the element.
        /// </param>
        private void SetXmlElement(XmlElement element, XmlNode parentNode)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            if (parentNode == null)
            {
                throw new ArgumentNullException("parentNode");
            }

            XmlElement existingElement =
                parentNode.SelectSingleNode(element.LocalName) as XmlElement;
            if (existingElement == null)
            {
                parentNode.AppendChild(element);
            }
            else
            {
                parentNode.ReplaceChild(element, existingElement);
            }
        }

        /// <summary>
        /// Checks to see if the maximum width element is present.
        /// </summary>
        /// <returns>
        /// true if the element is present and false otherwise.
        /// </returns>
        private bool MaxWidthExists()
        {
            XmlElement maxWidthElement =
                this.publishParametersNode.SelectSingleNode("MaxWidth") as XmlElement;
            return maxWidthElement != null;
        }

        /// <summary>
        /// Gets the maximum width a photo should be published at.
        /// </summary>
        /// <returns>
        /// The maximum width a photo should be published at.
        /// </returns>
        private int GetMaxWidth()
        {
            XmlElement maxWidthElement = GetXmlElement("MaxWidth", this.publishParametersNode);
            int.TryParse(maxWidthElement.InnerText, NumberStyles.Integer, CultureInfo.InvariantCulture, out maxWidth);
            return maxWidth;
        }

        /// <summary>
        /// Sets the maximum width a photo should be published at.
        /// </summary>
        /// <param name="maxWidth">
        /// The maximum width a photo should be published at.
        /// </param>
        private void SetMaxWidth(int maxWidth)
        {
            XmlElement maxWidthElement = GetXmlElement("MaxWidth", this.publishParametersNode);
            maxWidthElement.InnerText = maxWidth.ToString();
        }

        /// <summary>
        /// Checks to see if the maximum height element is present.
        /// </summary>
        /// <returns>
        /// true if the element is present and false otherwise.
        /// </returns>
        private bool MaxHeightExists()
        {
            XmlElement maxHeightElement =
                this.publishParametersNode.SelectSingleNode("MaxHeight") as XmlElement;
            return maxHeightElement != null;
        }

        /// <summary>
        /// Gets the maximum height a photo should be published at.
        /// </summary>
        /// <returns>
        /// The maximum height a photo should be published at.
        /// </returns>
        private int GetMaxHeight()
        {
            XmlElement maxHeightElement = GetXmlElement("MaxHeight", this.publishParametersNode);
            int.TryParse(maxHeightElement.InnerText, NumberStyles.Integer, CultureInfo.InvariantCulture, out maxHeight);
            return maxHeight;
        }

        /// <summary>
        /// Sets the maximum height a photo should be published at.
        /// </summary>
        /// <param name="maxHeight">
        /// The maximum height a photo should be published at.
        /// </param>
        private void SetMaxHeight(int maxHeight)
        {
            XmlElement maxHeightElement = GetXmlElement("MaxHeight", this.publishParametersNode);
            maxHeightElement.InnerText = maxHeight.ToString();
        }

        /// <summary>
        /// Checks to see if a Facebook API key is present.
        /// </summary>
        /// <returns>
        /// true if an API key is present and false otherwise.
        /// </returns>
        private bool ApiKeyExists()
        {
            XmlElement apiKeyElement =
                this.publishParametersNode.SelectSingleNode("ApiKey") as XmlElement;
            return apiKeyElement != null;
        }

        /// <summary>
        /// Gets the Facebook API key.
        /// </summary>
        /// <returns>
        /// The Facebook API key.
        /// </returns>
        private string GetApiKey()
        {
            XmlElement apiKeyElement = 
                GetXmlElement("ApiKey", this.publishParametersNode);
            return apiKeyElement.InnerText;
        }

        /// <summary>
        /// Sets the Facebook API key to the specified string.
        /// </summary>
        /// <param name="apiKey">
        /// The API key to set.
        /// </param>
        private void SetApiKey(string apiKey)
        {
            if (apiKey == null)
            {
                throw new ArgumentNullException("apiKey");
            }

            XmlElement apiKeyElement = this.sessionXml.CreateElement("ApiKey");
            apiKeyElement.InnerText = apiKey;

            SetXmlElement(apiKeyElement, this.publishParametersNode);
        }

        /// <summary>
        /// Checks to see if a Facebook API secret is present.
        /// </summary>
        /// <returns>
        /// true if an API secret is present and false otherwise.
        /// </returns>
        private bool ApiSecretExists()
        {
            XmlElement apiSecretElement =
                this.publishParametersNode.SelectSingleNode("ApiSecret") as XmlElement;
            return apiSecretElement != null;
        }

        /// <summary>
        /// Gets the Facebook API secret.
        /// </summary>
        /// <returns>
        /// The Facebook API secret.
        /// </returns>
        private string GetApiSecret()
        {
            XmlElement apiSecretElement = GetXmlElement("ApiSecret", this.publishParametersNode);
            return apiSecretElement.InnerText;
        }

        /// <summary>
        /// Sets the Facebook API secret to the specified string.
        /// </summary>
        /// <param name="apiSecret">
        /// The API secret to set.
        /// </param>
        private void SetApiSecret(string apiSecret)
        {
            if (apiSecret == null)
            {
                throw new ArgumentNullException("apiSecret");
            }

            XmlElement apiSecretElement = this.sessionXml.CreateElement("ApiSecret");
            apiSecretElement.InnerText = apiSecret;

            SetXmlElement(apiSecretElement, this.publishParametersNode);
        }

        /// <summary>
        /// Checks to see if a user is present.
        /// </summary>
        /// <returns>
        /// true if a user is present and false otherwise.
        /// </returns>
        private bool UserExists()
        {
            XmlElement userElement =
                this.publishParametersNode.SelectSingleNode("user") as XmlElement;
            return userElement != null;
        }

        /// <summary>
        /// Gets the Facebook user to upload with.
        /// </summary>
        /// <returns>
        /// The Facebook user to upload with.
        /// </returns>
        private Account GetUser()
        {
            XmlElement userElement = GetXmlElement("user", this.publishParametersNode);
            return FacebookParser.DeserializeAccount(userElement);
        }

        /// <summary>
        /// Sets the Facebook user to upload with.
        /// </summary>
        /// <param name="user">
        /// The Facebook user to upload with.
        /// </param>
        private void SetUser(Account user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            XmlElement userElement = FacebookParser.SerializeAccount(user, this.sessionXml);
            SetXmlElement(userElement, this.publishParametersNode);
        }

        /// <summary>
        /// Checks if an album is present.
        /// </summary>
        /// <returns>
        /// true if an album is present and false otherwise.
        /// </returns>
        private bool AlbumExists()
        {
            XmlElement albumElement =
                this.publishParametersNode.SelectSingleNode("album") as XmlElement;
            return albumElement != null;
        }

        /// <summary>
        /// Gets the album to upload to.
        /// </summary>
        /// <returns>
        /// The album to upload to.
        /// </returns>
        private Album GetAlbum()
        {
            XmlElement albumElement = GetXmlElement("album", this.publishParametersNode);
            return FacebookParser.DeserializeAlbum(albumElement);
        }

        /// <summary>
        /// Sets the album to upload to.
        /// </summary>
        /// <param name="album">
        /// The album to upload to.
        /// </param>
        private void SetAlbum(Album album)
        {
            if (album != null)
            {
                // Album can be null if we're only uploading videos.
                XmlElement albumElement = FacebookParser.SerializeAlbum(album, this.sessionXml);
                SetXmlElement(albumElement, this.publishParametersNode);
            }
        }

        /// <summary>
        /// Checks to see if the item set exists.
        /// </summary>
        /// <returns>
        /// true if item set exists and false otherwise. Should always return true.
        /// </returns>
        private bool ItemSetExists()
        {
            XmlElement itemSetElement =
                this.sessionXml.DocumentElement.SelectSingleNode("ItemSet") as XmlElement;
            return itemSetElement != null;
        }

        /// <summary>
        /// Gets the list of items to upload.
        /// </summary>
        /// <returns>
        /// A list of items to upload.
        /// </returns>
        private List<Item> GetItemSet()
        {
            XmlElement itemSetElement = GetXmlElement("ItemSet", this.sessionXml.DocumentElement);
            XmlNodeList itemNodes = itemSetElement.SelectNodes("Item");

            List<Item> itemSet = new List<Item>();
            this.uniquePeopleTags = new Dictionary<string, PersonTag>();
            foreach (XmlElement itemElement in itemNodes)
            {
                string id = itemElement.GetAttribute("id");
                string filePath = GetXmlElement("FullFilePath", itemElement).InnerText;
                string fileName = GetXmlElement("OriginalFileName", itemElement).InnerText;
                string fileExtension = GetXmlElement("OriginalFileExtension", itemElement).InnerText;
                string perceivedType = GetXmlElement("PerceivedType", itemElement).InnerText;
                string title = GetXmlElement("Title", itemElement).InnerText;

                int width;
                int.TryParse(GetXmlElement("OriginalWidth", itemElement).InnerText, 
                    NumberStyles.Integer, CultureInfo.InvariantCulture, out width);

                int height;
                int.TryParse(GetXmlElement("OriginalHeight", itemElement).InnerText, 
                    NumberStyles.Integer, CultureInfo.InvariantCulture, out height);

                int lengthMS;
                int.TryParse(GetXmlElement("LengthMS", itemElement).InnerText, 
                    NumberStyles.Integer, CultureInfo.InvariantCulture, out lengthMS);

                double fileSize;
                double.TryParse(GetXmlElement("FileSize", itemElement).InnerText, 
                    NumberStyles.Integer, CultureInfo.InvariantCulture, out fileSize);

                List<string> keywordSet = new List<string>();
                XmlNodeList keywords = itemElement.SelectNodes("KeywordSet/Keyword");
                foreach (XmlNode keyword in keywords)
                {
                    keywordSet.Add(keyword.InnerText);
                }

                List<PersonTag> personTagSet = new List<PersonTag>();
                XmlNodeList personTags = itemElement.SelectNodes("PeopleRegionSet/PersonRegion");
                foreach (XmlElement personTag in personTags)
                {
                    float x = 0.0f, y = 0.0f, w = 0.0f, h = 0.0f;
                    bool success = float.TryParse(personTag.GetAttribute("left"), 
                        NumberStyles.Float, CultureInfo.InvariantCulture, out x);
                    success = success && float.TryParse(personTag.GetAttribute("top"), 
                        NumberStyles.Float, CultureInfo.InvariantCulture, out y);
                    success = success && float.TryParse(personTag.GetAttribute("width"), 
                        NumberStyles.Float, CultureInfo.InvariantCulture, out w);
                    success = success && float.TryParse(personTag.GetAttribute("height"), 
                        NumberStyles.Float, CultureInfo.InvariantCulture, out h);
                    if (success)
                    {
                        PersonTag thisTag = new PersonTag(personTag.InnerText, x, y, w, h, filePath);
                        personTagSet.Add(thisTag);

                        string key = thisTag.Name.ToLower();
                        if (!uniquePeopleTags.ContainsKey(key))
                        {
                            uniquePeopleTags[key] = thisTag;
                        }
                    }
                }

                string description = string.Empty;
                XmlElement descriptionElement = itemElement.SelectSingleNode("Description") as XmlElement;
                if (descriptionElement != null)
                {
                    description = descriptionElement.InnerText;
                }

                string link = string.Empty;
                XmlElement linkElement = itemElement.SelectSingleNode("Link") as XmlElement;
                if (linkElement != null)
                {
                    link = linkElement.InnerText;
                }

                Item newItem = new Item(id, filePath, fileName, fileExtension, perceivedType, title, 
                    width, height, lengthMS, fileSize, keywordSet, personTagSet, description, link);
                itemSet.Add(newItem);
            }

            return itemSet;
        }

        /// <summary>
        /// Set a list of items to upload.
        /// </summary>
        /// <param name="itemSet">
        /// A list of items to upload. The only parameter of an Item that should have changed is Link.
        /// </param>
        private void SetItemSet(List<Item> itemSet)
        {
            if (itemSet == null)
            {
                throw new ArgumentNullException("itemSet");
            }

            XmlElement itemSetElement = GetXmlElement("ItemSet", this.sessionXml.DocumentElement);

            foreach (Item item in itemSet)
            {
                XmlElement itemElement =
                    GetXmlElement(string.Format("Item[@id='{0}']", item.Id), itemSetElement);

                XmlElement titleElement = this.sessionXml.CreateElement("Title");
                titleElement.InnerText = item.Title;
                SetXmlElement(titleElement, itemElement);

                XmlElement descriptionElement = this.sessionXml.CreateElement("Description");
                descriptionElement.InnerText = item.Description;
                SetXmlElement(descriptionElement, itemElement);

                XmlElement linkElement = this.sessionXml.CreateElement("Link");
                linkElement.InnerText = item.Link;
                SetXmlElement(linkElement, itemElement);
            }
        }


        /// <summary>
        /// Checks to see if the log exists.
        /// </summary>
        /// <returns>
        /// true if the log exists and false otherwise.
        /// </returns>
        private bool LogExists()
        {
            XmlElement logElement =
                this.sessionXml.DocumentElement.SelectSingleNode("Log") as XmlElement;
            return logElement != null;
        }

        /// <summary>
        /// Gets a list of log items.
        /// </summary>
        /// <returns>
        /// A list of log items from the log.
        /// </returns>
        private List<LogItem> GetLog()
        {
            XmlElement logElement = GetXmlElement("Log", this.sessionXml.DocumentElement);
            XmlNodeList logItemNodes = logElement.SelectNodes("Action");

            List<LogItem> log = new List<LogItem>();
            foreach(XmlElement logItemElement in logItemNodes)
            {
                bool successful = logItemElement.GetAttribute("successful") == bool.TrueString;
                string message = logItemElement.InnerText;

                if (successful)
                {
                    log.Add(new LogItem(LogItem.Outcome.Successful, message));
                }
                else
                {
                    log.Add(new LogItem(LogItem.Outcome.Unsuccessful, message));
                }
            }

            return log;
        }

        /// <summary>
        /// Sets a list of log items.
        /// </summary>
        /// <param name="log">
        /// A list of log items.
        /// </param>
        private void SetLog(List<LogItem> log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }

            XmlElement logElement = this.sessionXml.CreateElement("Log");

            foreach (LogItem upload in log)
            {
                XmlElement uploadElement = this.sessionXml.CreateElement("Action");
                uploadElement.InnerText = upload.Message;

                uploadElement.SetAttribute("successful",
                    upload.Successful ? bool.TrueString : bool.FalseString);

                logElement.AppendChild(uploadElement);
            }

            SetXmlElement(logElement, this.sessionXml.DocumentElement);
        }

        /// <summary>
        /// Checks to see if a friend list exists.
        /// </summary>
        /// <returns>
        /// true if the friend exists and false otherwise.
        /// </returns>
        private bool FriendListExists()
        {
            XmlElement friendElement =
                this.sessionXml.DocumentElement.SelectSingleNode("Friends") as XmlElement;
            return friendElement != null;
        }

        /// <summary>
        /// Gets the list of friends.
        /// </summary>
        /// <returns>
        /// A list of friends.
        /// </returns>
        private List<Friend> GetFriendList()
        {
            XmlElement friendsElement = GetXmlElement("Friends", this.sessionXml.DocumentElement);
            XmlNodeList friendNodes = friendsElement.SelectNodes("user");

            List<Friend> friendList = new List<Friend>();
            foreach (XmlElement friendElement in friendNodes)
            {
                friendList.Add(FacebookParser.DeserializeFriend(friendElement));
            }

            return friendList;
        }

        /// <summary>
        /// Sets the friend list.
        /// </summary>
        /// <param name="friendList">
        /// The list of friends.
        /// </param>
        private void SetFriendList(List<Friend> friendList)
        {
            if (friendList == null)
            {
                throw new ArgumentNullException("friendList");
            }

            XmlElement friendsElement = this.sessionXml.CreateElement("Friends");
            foreach (Friend friendObject in friendList)
            {
                XmlElement friendElement = FacebookParser.SerializeFriend(friendObject, this.sessionXml);
                friendsElement.AppendChild(friendElement);
            }

            SetXmlElement(friendsElement, this.sessionXml.DocumentElement);
        }

        /// <summary>
        /// Checks to see if the AccountLinks element is present.
        /// </summary>
        /// <returns>
        /// true if the element is present and false otherwise.
        /// </returns>
        private bool AccountLinksExists()
        {
            XmlElement accountLinksElement =
                this.sessionXml.DocumentElement.SelectSingleNode("AccountLinks") as XmlElement;
            return accountLinksElement != null;
        }

        /// <summary>
        /// Gets a list of all account links.
        /// </summary>
        /// <returns>
        /// A list of account links.
        /// </returns>
        private List<AccountLink> GetAccountLinks()
        {
            XmlElement accountLinksElement = GetXmlElement("AccountLinks", this.sessionXml.DocumentElement);

            List<AccountLink> accountLinks = new List<AccountLink>();

            XmlNodeList accountLinksNodes = accountLinksElement.SelectNodes("account_link");
            foreach (XmlElement accountLinkElement in accountLinksNodes)
            {
                AccountLink accountLink = FacebookParser.DeserializeAccountLink(accountLinkElement);
                accountLinks.Add(accountLink);
            }

            return accountLinks;
        }

        /// <summary>
        /// Sets a list of account links.
        /// </summary>
        /// <param name="users">
        /// The list of account links to set.
        /// </param>
        private void SetAccountLinks(List<AccountLink> accountLinks)
        {
            if (accountLinks == null)
            {
                throw new ArgumentNullException("AccountLinks");
            }

            XmlElement accountLinksElement = this.sessionXml.CreateElement("AccountLinks");

            foreach (AccountLink accountLink in accountLinks)
            {
                accountLinksElement.AppendChild(FacebookParser.SerializeAccountLink(accountLink, this.sessionXml));
            }

            SetXmlElement(accountLinksElement, this.sessionXml.DocumentElement);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Sets all of the public properties back into the XmlDocument.
        /// </summary>
        public void Save()
        {
            SetMaxWidth(this.maxWidth);
            SetMaxHeight(this.maxHeight);
            SetApiKey(this.apiKey);
            SetApiSecret(this.apiSecret);
            SetUser(this.user);
            SetAlbum(this.album);
            SetFriendList(this.friendList);
            SetItemSet(this.itemSet);
            SetLog(this.log);
            SetAccountLinks(this.accountLinks);
        }

        #endregion
    }
}